﻿/*****************************************************************************
 * Hyldahl.Services.TaskProcessing                 Created by: MSH 2008.07.22
 * --------------------------------------------------------------------------
 * FileName: Data\TaskDataProvider.cs
 * --------------------------------------------------------------------------
 * Copyright 2009 Martin Sixhøj Hyldahl
 *****************************************************************************/

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Configuration.Provider;
using System.Reflection;

namespace Hyldahl.Services.TaskProcessing.Data
{
    public abstract class TaskDataProvider : System.Configuration.Provider.ProviderBase
    {
        /*****************************************************
         * FIELDS
         *****************************************************/
        private string  connectionString;
        private Dictionary<Type, Dictionary<string, PropertyInfo>> typePropertyCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

        /*****************************************************
         * METHODS
         *****************************************************/

        /// <summary>
        /// Initializes the provider.
        /// </summary>
        /// <param name="name">The friendly name of the provider.</param>
        /// <param name="config">A collection of the name/value pairs representing the provider-specific attributes specified in the configuration for this provider.</param>
        /// <exception cref="T:System.ArgumentNullException">The name of the provider is null.</exception>
        /// <exception cref="T:System.ArgumentException">The name of the provider has a length of zero.</exception>
        /// <exception cref="T:System.InvalidOperationException">An attempt is made to call <see cref="M:System.Configuration.Provider.ProviderBase.Initialize(System.String,System.Collections.Specialized.NameValueCollection)"/> on a provider after the provider has already been initialized.</exception>
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException("config");

            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
                name = "ConfigurationStoreDataSqlProvider";

            // Add a default "description" attribute to config if the
            // attribute doesn't exist or is empty
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "Configuration Store SQL Provider");
            }

            base.Initialize(name, config);

            string connect = config["connectionStringName"];

            if (String.IsNullOrEmpty(connect))
                throw new ProviderException("Empty or missing connectionStringName");

            config.Remove("connectionStringName");

            if (ConfigurationManager.ConnectionStrings[connect] == null)
                throw new ProviderException("Missing connection string");

            this.ConnectionString = ConfigurationManager.ConnectionStrings[connect].ConnectionString;

            if (String.IsNullOrEmpty(this.ConnectionString))
                throw new ProviderException("Empty connection string");
        }

        /*****************************************************
         * DATA METHODS
         *****************************************************/

        /// <summary>
        /// Creates the task.
        /// </summary>
        /// <param name="task">The task.</param>
        public abstract void CreateTask(Task task);

        /// <summary>
        /// Saves the task result.
        /// </summary>
        /// <param name="task">The task.</param>
        public abstract void SaveTaskResult(Task task);

        /// <summary>
        /// Gets the tasks.
        /// </summary>
        /// <returns></returns>
        public abstract Collection<Task> GetTasks();

        /// <summary>
        /// Gets the task.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public abstract Task GetTask(Guid id);

        /// <summary>
        /// Gets the an unprocessed task.
        /// </summary>
        /// <returns></returns>
        public abstract Task GetUnProcessedTask();

        /*****************************************************
         * VALIDATION METHODS
         *****************************************************/

        /// <summary>
        /// Validates the task for creation.
        /// </summary>
        /// <param name="task">The task.</param>
        protected void ValidateTaskForCreation(Task task)
        {
            if (task == null)
                throw new ArgumentNullException("task");

            if (task.IsProcessed)
                throw new ArgumentException("Task has already been processed", "task");

            if (task.Id == Guid.Empty)
                task.Id = Guid.NewGuid();

            if (task.CreatedDate == DateTime.MinValue)
                task.CreatedDate = DateTime.UtcNow;
        }

        /*****************************************************
         * PROPERTIES
         *****************************************************/

        /// <summary>
        /// Gets or sets the connection string.
        /// </summary>
        /// <value>The connection string.</value>
        protected string ConnectionString
        {
            get
            {
                return connectionString;
            }
            set
            {
                connectionString = value;
            }
        }
    }
}
